package com.knowledge.web.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.IdUtil;
import com.knowledge.model.pojo.Result;
import com.knowledge.model.pojo.UploadInfo;
import com.knowledge.serve.service.UploadFileService;
import com.knowledge.common.utils.FileTools;
import com.knowledge.common.utils.RedisTools;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.Objects;

@RestController
@RequestMapping("/api")
@Api(tags = "文件上传")
@Slf4j
public class UploadController {

    @Autowired
    private UploadFileService uploadFileService;

    @Autowired
    private RedisTools redisTools;

    @Autowired
    private FileTools fileTools;


    @PostMapping("/upload/file")
    @ApiOperation("上传大文件切片")
    public Result uploadBidFile(MultipartFile multipartFile,
                                String fileMd5, //文件加密后的md5文件
                                Integer chunkIndex,//当前切片
                                Integer chunks //切片个数
    ){
        //切片个数判断
        if(chunkIndex>chunks){
            return Result.error("超过最大切片的个数，请重新上传");
        }

        //临时文件目录对象信息
        File tmpFileFolder = null;
        boolean uploadStatus = true;//上传状态
        File newFile = null;//上传的文件切片对象
        UploadInfo uploadInfo = new UploadInfo();
        try {
            //定义临时目录对象信息
            String tmpDir = System.getProperty("user.dir")+"/uploads/tmp/";
            tmpFileFolder = new File(tmpDir+fileMd5);//实例化File对象
            //目录不存在就生成目录
            if(!tmpFileFolder.exists()){
                tmpFileFolder.mkdirs();
            }
            //传递过来的新文件，通过md5的文件夹+切片值生成对象
            newFile = new File(tmpFileFolder.getPath()+"/"+chunkIndex);
            //如果当前切片存在，并且文件的大小都是一样的，那么基本上可以断定是同一个文件，直接返回不再重新存储, 这就相当于断点续传，可以在前端页处理一下，减少网络请求
            if(newFile.exists() && newFile.length() == multipartFile.getSize()){
                uploadInfo.setFileStatus(4500);
                uploadInfo.setChunkIndex(chunkIndex);
                uploadInfo.setMessage("切片上传过来了");
                return Result.success(uploadInfo);
            }

            //执行文件存储操作
            multipartFile.transferTo(newFile);
        }catch (Exception e){
            e.printStackTrace();//执行失败，删除临时目录文件
            uploadStatus = false;
            uploadInfo.setFileStatus(5000);
            uploadInfo.setChunkIndex(chunkIndex);
            uploadInfo.setMessage("上传失败");
            log.error("文件上传失败",e.getMessage());

            return Result.success(uploadInfo);
        }finally {
            if(!uploadStatus && Objects.nonNull(newFile)){
                FileUtil.del(newFile);
            }
        }

        uploadInfo.setFileStatus(4500);
        uploadInfo.setChunkIndex(chunkIndex);
        uploadInfo.setMessage("切片上传过来了");
        return Result.success(uploadInfo);
    }

    @PostMapping("/union/file")
    @ApiOperation("切片合并接口")
    public Result unionFile(String fileName,String fileMd5){
        //先定义临时目录变量
        String tmpFileFolder = null;
        log.info("文件名:{},加密后的md5:{}",fileName,fileMd5);
        try {
            //文件夹的核心路径，以日期作为文件夹生成内容
            String monthDay = DateUtil.format(new Date(),"yyyyMMdd");

            //生成的文件的名字是什么，真实名字，处理过的
            String realFileName = IdUtil.simpleUUID().substring(0,8)+"_"+fileName;
            //临时目录信息，用于合成文件的源文件
            tmpFileFolder = System.getProperty("user.dir")+"/uploads/tmp/"+fileMd5;

            //合并生成的目录是什么
            String targetFolderName = System.getProperty("user.dir")+"/uploads/"+monthDay;
            File targetFolder = new File(targetFolderName);
            //目录不存在，生成目录
            if(!targetFolder.exists()){
                targetFolder.mkdirs();
            }

            //最终的目标文件，合并生成的文件对象
            String targetFileName = targetFolderName+"/"+fileName;
            FileTools.unionFile(tmpFileFolder,targetFileName,realFileName,true);

            //把内容填充到数据库中取
//            uploadFileService.addFileRecord(fileMd5,targetFileName);
            //添加到redis中去,md5是key，文件夹路径是value
            redisTools.set(fileMd5,targetFileName);
        }catch (Exception e){
            e.printStackTrace();
            log.error("文件合并失败:{}",e.getMessage());
        }
        return Result.success("文件合并成功");
    }


    @GetMapping("/query/file/{md5}")
    @ApiOperation("查询文件是否存在")
    public Result queryUploadFile(@PathVariable("md5") String fileMd5){
        log.info("用户传递过来的md5文件信息是:{}",fileMd5);
        UploadInfo uploadInfo = new UploadInfo();
        if(fileMd5.length() < 0){
            return Result.error("md5必须得传递");
        }

//        Integer count = uploadFileService.getFileByMd5(fileMd5);
        Object fileData = redisTools.get(fileMd5);
        log.info("个数:{}",fileData);

        if(fileData !=null){
            uploadInfo.setFileStatus(4500);
//            uploadInfo.setChunkIndex(chunkIndex);
            uploadInfo.setMessage("切片上传过来了");
            return Result.success(uploadInfo);
        }

        return Result.success();
    }

    /**
     * @desc 上传文件到OSS中去
     * @param file
     * @return
     */
    @PostMapping("/oss/upload/file")
    @ApiOperation("上传文件到OSS中")
    public Result uploadFileToOss(@RequestParam(value = "file") MultipartFile file){
        log.info("上传文件内容:{}",file);
        try{
            if(file.isEmpty()){
                return Result.error("上传文件内容为空,请重新选择文件");
            }

            String filePath = fileTools.uploadOss(file);

            HashMap<String, String> data = new HashMap<>();
            data.put("path",filePath);
            return Result.success(data);
        }catch (Exception e){
            log.error("文件上传失败:{}",e.getMessage());
            return Result.error(e.getMessage());
        }
    }
}
